package com.spukmk3me.resource;

import java.io.IOException;

/* $if SPUKMK3ME_DEBUG$ */
import com.spukmk3me.debug.Logger;
/* $endif$ */
import com.spukmk3me.io.FileHandle;
import com.spukmk3me.util.ReferenceCounted;

public abstract class Resource extends ReferenceCounted
{
    protected Resource()
    {
        m_state = NULL;
    }
    
    public final byte getState()
    {
        return m_state;
    }
    
    public final FileHandle getFileHandle()
    {
        return m_fileHandle;
    }
    
    public final String getType()
    {
        return m_type;
    }
    
    public final ResourceCreationDetails getCreationDetails()
    {
        return m_details;
    }

    final synchronized boolean assign( FileHandle handle, String type, ResourceCreationDetails details )
    {
        if ( m_state == NULL )
        {
            m_fileHandle    = handle;
            m_type          = type;
            m_details       = details;
            m_state         = ASSIGNED;
            return true;
        }
        else
        {
            /* $if SPUKMK3ME_DEBUG$ */
            Logger.trace( "Assigning resource which is not in null state." );
            /* $endif$ */
            return false;
        }
    }

    /**
     *   @return 0 if loaded successfully. Non-zero values indicate errors.
     *    Common error codes must be used by implementations.
     *      -1  : Not in ASSIGNED state.
     *    Other codes can be freely used.
     *   @throws IOException If there's IOException.
     */
    final synchronized int load() throws IOException
    {
        if ( m_state == ASSIGNED )
        {
            int returnCode;
            
            m_state = LOADING;
            returnCode = _load();
            
            if ( returnCode == 0 )
                m_state = READY;
            else
                m_state = ASSIGNED;
            
            return returnCode;
        }
        else
        {
            /* $if SPUKMK3ME_DEBUG$ */
            Logger.trace( "Loading resource which is not in assgined state." );
            /* $endif$ */
            return -1;
        }
    }

    final synchronized boolean release()
    {
        if ( m_state == READY )
        {
            m_state = RElEASING;
            _release();
            m_state = ASSIGNED;
            return true;
        }
        else
        {
            /* $if SPUKMK3ME_DEBUG$ */
            Logger.trace( "Releasing resource which is not in assgined state." );
            /* $endif$ */
            return false;
        }
    }
    
    @Override
    public synchronized final void onZeroCounter()
    {
        if ( getState() == READY )
        {
            /* $if SPUKMK3ME_DEBUG$ */
            Logger.log( "Removing resource: " + m_fileHandle.toString() + "..." );
            /* $endif$ */
            release();
            /* $if SPUKMK3ME_DEBUG$ */
            Logger.log( "done\n" );
            /* $endif$ */
        }
    }
    
    protected abstract void _release();
    protected abstract int _load() throws IOException;
    
    public static final byte NULL       = 0;
    public static final byte ASSIGNED   = 1;
    public static final byte LOADING    = 2;
    public static final byte READY      = 3;
    public static final byte RElEASING  = 4;
    
    private FileHandle              m_fileHandle;
    private ResourceCreationDetails m_details;
    private String                  m_type;
    private byte                    m_state;
}
